package com.hksj.acm.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.hksj.acm.dto.AlarmKindNumDTO;
import com.hksj.acm.dto.CockpitAlarmDTO;
import com.hksj.acm.dto.CockpitDeviceDTO;
import com.hksj.acm.mapper.CockpitMapper;
import com.hksj.acm.vo.*;
import com.hksj.cbm.dto.AlarmDTO;
import com.hksj.cbm.dto.DeviceDTO;
import com.hksj.cbm.entity.DeviceMetadataParseInfo;
import com.hksj.cbm.mapper.DeviceMetadataParseInfoMapper;
import com.hksj.cbm.service.AlarmService;
import com.hksj.cbm.service.DeviceInstanceService;
import com.hksj.cbm.vo.AlarmVO;
import com.hksj.cbm.vo.DeriveMetadataVO;
import com.hksj.cbm.vo.SpaceModelVO;
import com.hksj.common.core.common.Constants;
import com.hksj.common.core.common.SpecialityModelCodeEnum;
import com.hksj.common.core.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author fjt
 * @data 2024/7/17 10:07
 * @describe 驾驶舱
 */
@Slf4j
@Service
public class CockpitService {


    @Autowired
    private AlarmService alarmService;
    @Autowired
    private CockpitMapper cockpitMapper;
    @Autowired
    private DeviceMetadataParseInfoMapper deviceMetadataParseInfoMapper;
    @Autowired
    private DeviceInstanceService deviceInstanceService;
    @Autowired
    private DeviceService deviceService;



    /**
     * 查询指定时间内的报警/故障记录
     * @param dto
     * @return
     */
    public List<CockpitAlarmListVO> queryAlarmListByTime(CockpitAlarmDTO dto){
        dto.setCode(SpecialityModelCodeEnum.air_conditioning.getCode());
        AlarmDTO alarmDTO = new AlarmDTO();
        BeanUtils.copyProperties(dto, alarmDTO);
        List<AlarmVO> alarmList = alarmService.list(alarmDTO);
        if (CollUtil.isEmpty(alarmList)){
            return null;
        }

        List<CockpitAlarmListVO> voList = new ArrayList<>(alarmList.size());
        alarmList.forEach(alarmVO -> {
            CockpitAlarmListVO vo = new CockpitAlarmListVO();
            BeanUtils.copyProperties(alarmVO, vo);
            // 经产品确认设备位置只要楼层
            List<SpaceModelVO> spaceModelVOList = alarmVO.getSpaceModelVOList();
            if (CollUtil.isNotEmpty(spaceModelVOList)){
                SpaceModelVO spaceModelVO = spaceModelVOList.stream()
                        .filter(item -> Constants.THREE_STR.equals(item.getSpaceItemValue())).findFirst().get();
                // 3-楼层
                vo.setPathName(spaceModelVO.getModelName());
            }
            voList.add(vo);
        });
        return voList;
    }


    /**
     * 按天统计指定时间内的温湿度报警数量
      * @param dto
     * @return
     */
    public List<AlarmKindNumVO> queryHistoryAlarmNumByTime(AlarmKindNumDTO dto){
        Assert.notNull(dto.getStartTime(), "查询起始时间不能为空");
        Assert.notNull(dto.getEndTime(), "查询截止时间不能为空");
        dto.setCode(SpecialityModelCodeEnum.air_conditioning.getCode());
        // 查温度
        dto.setProperty("wd");
        List<AlarmNumVO> temperatureList = cockpitMapper.queryHistoryAlarmNumByTime(dto);
        Map<String, Integer> temperatureMap = temperatureList.stream().collect(Collectors.toMap(p -> p.getCreateTime(), p -> p.getNum()));

        // 查湿度
        dto.setProperty("sd");
        List<AlarmNumVO> humidityList = cockpitMapper.queryHistoryAlarmNumByTime(dto);
        Map<String, Integer> humidityMap = humidityList.stream().collect(Collectors.toMap(p -> p.getCreateTime(), p -> p.getNum()));

        List<LocalDate> dateList = DateUtil.getDatesInRange(DateUtil.convertToLocalDate(dto.getStartTime()), DateUtil.convertToLocalDate(dto.getEndTime()));
        List<AlarmKindNumVO> voList = new ArrayList<>(dateList.size());
        dateList.forEach(date -> {
            String dateStr = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            AlarmKindNumVO kindNumVO = AlarmKindNumVO.builder().createTime(date)
                    .humidityAlarmNum(humidityMap.get(dateStr)).temperatureAlarmNum(temperatureMap.get(dateStr))
                    .build();
            voList.add(kindNumVO);
        });
        return voList;
    }


    /**
     * 统计设备当前报警数量
     * @param dto
     * @return
     */
    public CurrentAlarmNumVO currentAlarmNum(AlarmKindNumDTO dto){
        dto.setCode(SpecialityModelCodeEnum.air_conditioning.getCode());
        dto.setAlarmType(Constants.TWO);// 2=机组故障记录
        Integer unitMalfunctionNum = cockpitMapper.currentAlarmNum(dto);
        // 查温度报警数量
        dto.setAlarmType(Constants.ONE);// 1=设备报警记录
        dto.setProperty("wd");
        Integer temperatureAlarmNum = cockpitMapper.currentAlarmNum(dto);
        // 查湿度报警数量
        dto.setProperty("sd");
        Integer humidityAlarmNum = cockpitMapper.currentAlarmNum(dto);
        return CurrentAlarmNumVO.builder().unitMalfunctionNum(unitMalfunctionNum)
                .temperatureAlarmNum(temperatureAlarmNum).humidityAlarmNum(humidityAlarmNum).build();
    }


    /**
     * 查询设备当前报警列表
     * @param dto
     * @return
     */
    public List<CockpitAlarmListVO> currentAlarmList(AlarmKindNumDTO dto){
        dto.setCode(SpecialityModelCodeEnum.air_conditioning.getCode());
        List<CockpitAlarmListVO> list = cockpitMapper.currentAlarmList(dto);
        // 设置每个设备的空间位置节点信息
        List<String> pathList = list.stream().map(CockpitAlarmListVO::getPaths).collect(Collectors.toList());
        if (CollUtil.isEmpty(pathList)){
            return list;
        }
        Map<String, List<SpaceModelVO>> pathNameMap = deviceInstanceService.devicePathConvertToUTF8(pathList);
        if (CollUtil.isNotEmpty(pathNameMap)){
            list.forEach(alarmVO -> {
                // 经产品确认设备位置只要楼层
                List<SpaceModelVO> spaceModelVOList = pathNameMap.get(alarmVO.getPaths());
                if (CollUtil.isNotEmpty(spaceModelVOList)){
                    // 3-楼层
                    SpaceModelVO spaceModelVO = spaceModelVOList.stream()
                            .filter(item -> Constants.THREE_STR.equals(item.getSpaceItemValue())).findFirst().get();
                    alarmVO.setPathName(ObjectUtil.isNotNull(spaceModelVO) ? spaceModelVO.getModelName() : null);
                }
            });
        }
        return list;
    }


    /**
     * 查询设备列表
     * @param dto
     * @return
     */
    public List<CockpitDeviceVO> deviceList(CockpitDeviceDTO dto){
        DeviceDTO deviceDTO = new DeviceDTO();
        BeanUtils.copyProperties(dto, deviceDTO);
        // 1.获取符合要求的设备列表
        List<DeviceVO> deviceList = deviceService.deviceWithoutDataList(deviceDTO);
        if (CollUtil.isEmpty(deviceList)){
            return null;
        }

        List<String> deviceIdList = deviceList.stream().map(DeviceVO::getDeviceId).collect(Collectors.toList());
        // 2.获取每个设备最新的机组故障状态
        List<String> inAlarmDeviceList = alarmService.getUnitMalfunction(deviceIdList, Constants.TWO);

        List<CockpitDeviceVO> cockpitDeviceList = new ArrayList<>(deviceList.size());
        for(DeviceVO deviceVO : deviceList){
            // 3.处理设备路径
            CockpitDeviceVO cockpitDeviceVO = new CockpitDeviceVO();
            BeanUtils.copyProperties(deviceVO, cockpitDeviceVO);
            // 设备位置只要楼层
            String pathName = deviceVO.getPathName();
            if (StringUtils.isNotBlank(pathName)){
                cockpitDeviceVO.setPathName(pathName.split("-")[1]);
            }
            // 设置机组故障状态
            if (CollUtil.isNotEmpty(inAlarmDeviceList) && inAlarmDeviceList.contains(deviceVO.getDeviceId())){
                cockpitDeviceVO.setFaultState(Constants.ONE);
            }else {
                // 正常
                cockpitDeviceVO.setFaultState(Constants.ZERO);
            }
            cockpitDeviceList.add(cockpitDeviceVO);
        }

        // 4.获取每个设备的监测数据
        List<DeviceMetadataParseInfo> deviceMetadataParseInfoList = deviceMetadataParseInfoMapper.selectListByDeviceIdAndLikeProperty(deviceIdList);
        if (CollUtil.isNotEmpty(deviceMetadataParseInfoList)) {

            // 按设备id把监测数据分组
            Map<String, List<DeviceMetadataParseInfo>> deviceMap = deviceMetadataParseInfoList.stream()
                    .collect(Collectors.groupingBy(DeviceMetadataParseInfo::getDeviceId));
            // 每个监测指标的中文、值的数据类型等信息
            Map<String, Map<String, DeriveMetadataVO>> attributeMap = deviceInstanceService.batchQueryDeviceAttribute(deviceIdList);

            for(CockpitDeviceVO cockpitDeviceVO : cockpitDeviceList){
                // 5.获取设备的每个指标的中文名称和监测值
                Map<String, DeriveMetadataVO> deviceTargetMap = attributeMap.get(cockpitDeviceVO.getDeviceId());// 中文名称
                List<DeviceMetadataParseInfo> parseInfoList = deviceMap.get(cockpitDeviceVO.getDeviceId());// 监测值
                if (CollUtil.isEmpty(parseInfoList)){
                    continue;
                }

                // 获取每个指标的中文名称和监测值
                List<DeviceAttributeVO> attributeList = new ArrayList<>(parseInfoList.size());
                for(DeviceMetadataParseInfo parseInfo : parseInfoList){
                    DeviceAttributeVO attributeVO = DeviceAttributeVO.builder().key(parseInfo.getProperty()).unit(parseInfo.getUnit()).value(parseInfo.getValue()).build();
                    if (CollUtil.isNotEmpty(deviceTargetMap)){
                        DeriveMetadataVO metadataVO = deviceTargetMap.get(parseInfo.getProperty());
                        attributeVO.setKeyName(ObjectUtil.isNotNull(metadataVO) ? metadataVO.getKeyName() : null);
                    }
                    attributeList.add(attributeVO);
                }
                cockpitDeviceVO.setAttributeList(attributeList);
            }
        }
        return cockpitDeviceList;
    }


    /**
     * 设备概览(经自控确认，一个空调机组只会有一个传感器设备，各种监测指标数据都是这一个设备来采集)
     * @return
     */
    public DeviceOverviewVO deviceOverView(CockpitDeviceDTO dto){
        List<CockpitDeviceVO> deviceList = cockpitMapper.deviceOverView(dto,
                SpecialityModelCodeEnum.air_conditioning.getCode(), SpecialityModelCodeEnum.kongtjz_product.getCode());
        DeviceOverviewVO overviewVO = new DeviceOverviewVO();
        if (CollUtil.isEmpty(deviceList)){
            overviewVO.setAirConditionTotal(0);
            return overviewVO;
        }

        // 在线
        List<CockpitDeviceVO> onLineDeviceList = deviceList.stream().
                filter(device -> "online".equals(device.getState()))
                .collect(Collectors.toList());
        // 离线
        List<CockpitDeviceVO> offLineDeviceList = deviceList.stream().
                filter(device -> "offline".equals(device.getState()))
                .collect(Collectors.toList());

        // 未激活
        List<CockpitDeviceVO> notActiveList = deviceList.stream().
                filter(device -> "notActive".equals(device.getState()))
                .collect(Collectors.toList());

        overviewVO.setAirConditionTotal(deviceList.size());
        overviewVO.setOnLineNum(CollUtil.isNotEmpty(onLineDeviceList) ? onLineDeviceList.size() : 0);
        overviewVO.setOffLineNum(CollUtil.isNotEmpty(offLineDeviceList) ? offLineDeviceList.size() : 0);
        overviewVO.setNotActiveNum(CollUtil.isNotEmpty(notActiveList) ? notActiveList.size() : 0);

        // 查询这些设备有哪些当前处于机组故障报警中的
        List<String> deviceIdList = deviceList.stream().map(CockpitDeviceVO::getDeviceId).collect(Collectors.toList());
        List<String> inFaultDeviceIdList = alarmService.getUnitMalfunction(deviceIdList, Constants.TWO);
        if (CollUtil.isEmpty(inFaultDeviceIdList)){
            overviewVO.setFaultNum(0);
            overviewVO.setUnFaultNum(deviceList.size());
            return overviewVO;
        }
        List<CockpitDeviceVO> faultList = deviceList.stream()
                .filter(device -> inFaultDeviceIdList.contains(device.getDeviceId()))
                .collect(Collectors.toList());
        overviewVO.setFaultNum(faultList.size());
        // 取差集
        overviewVO.setUnFaultNum(CollUtil.subtract(deviceList, faultList).size());
        return overviewVO;
    }

}
